// 草图 - 阵列
import {
  BaseCommand,
  CommandDialog,
  CommandDialogPlacement,
  EventsRes,
  ICurve,
  KEYBOARD_KEY,
  ObjInfo,
} from '@amcax/base';
import { Picker2D, PickerMgr } from '@amcax/renderer';
import { CommandFormWrapper } from '@app-cad/common/components/command-form';
import { PickInputForFocus2D } from '@app-cad/common/components/command-form/auto-focus/pick-input';
import { NumberInputFormat } from '@app-cad/common/components/command-form/constants';
import { NonDialogPickableCommandForm } from '@app-cad/common/components/command-form/pickable';
import { renderSketch, sketchPreview } from '@app-cad/common/utils';
import i18n from '@app-cad/common/utils/i18next';
import { ctx2 } from '@app-cad/module';
import { wsApi } from '@app-cad/server';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
import { useEffect, useState } from 'react';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '../../../events/SketchEventCenter';
import { dimRender } from '../cmd-render-pick/render';

interface OffsetDialogProps {
  title: string;
  placement: CommandDialogPlacement;
  props: ObjInfo;
  onClose: () => void;
}

function OffsetCommand({ onClose, title }: OffsetDialogProps) {
  const sketchId = sketchEventCenter().getSketchInfo().sketchId;
  const [patternValue, setPatternValue] = useState([]);
  const [length, setLength] = useState(6);
  const [selectChain, setSelectChain] = useState(true);
  const [baseConstruct, setBaseConstruct] = useState(false);
  const [doubleDirect, setDoubleDirect] = useState(false);

  const picker = PickerMgr.getPicker<Picker2D>('2d');
  const formItemLayout = {
    labelCol: { span: 6 },
    wrapperCol: { span: 18 },
  };
  const schema: RJSFSchema = {
    type: 'object',
    properties: {
      length: {
        type: 'number',
        title: '间距',
        default: 6,
        format: NumberInputFormat.Length,
      },
      reverse: {
        type: 'boolean',
        title: '反向',
        default: false,
      },
      selectChain: {
        type: 'boolean',
        title: '选择链',
        default: true,
      },
      baseConstruct: {
        type: 'boolean',
        title: '构造元素',
        default: false,
      },
      doubleDirect: {
        type: 'boolean',
        title: '双向偏移',
        default: false,
      },
    },
  };
  const uiSchema: UiSchema = {
    'ui:options': {
      classNames: 'cmd-sketch-form-offset',
    },
  };

  useEffect(() => {
    sketchEventCenter()
      .setState('offset')
      .on(SKETCH_CENTEREVENTS.KEYUP, onKeyUp);

    return () => {
      sketchEventCenter().off(SKETCH_CENTEREVENTS.KEYUP, onKeyUp).setDefault();
      ctx2.cadScene.assisGroup.clear();
    };
  }, []);
  useEffect(() => {
    if (patternValue.length > 0) {
      ctx2.cadScene.assisGroup.clear();
      preview(length, true, selectChain, baseConstruct, doubleDirect);
    } else {
      ctx2.cadScene.assisGroup.clear();
    }
  }, [patternValue, length, selectChain, baseConstruct, doubleDirect]);
  const onPatternData = (ids: string[], picked: ICurve[]) => {
    setPatternValue(
      ['Circle', 'ArcOfCircle', 'Line'].includes(picked?.[0]?.type) ? ids : [],
    );
  };
  const onKeyUp = async (e: EventsRes<KeyboardEvent>) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      onClose();
    }
  };
  const onChange = async ({
    length,
    selectChain,
    baseConstruct,
    doubleDirect,
    reverse,
  }) => {
    // 这里需要判断null
    if (!length) {
      ctx2.cadScene.assisGroup.clear();
      ctx2.viewer.requestRender();
    } else {
      const newLength = reverse ? -length : length;
      if (patternValue && patternValue.length > 0) {
        await preview(
          newLength,
          true,
          selectChain,
          baseConstruct,
          doubleDirect,
        );
      }
      setLength(newLength);
      setSelectChain(selectChain);
      setBaseConstruct(baseConstruct);
      setDoubleDirect(doubleDirect);
    }
  };
  const preview = async (
    length,
    isPreview: boolean = true,
    selectChain: boolean = true,
    baseConstruct: boolean = false,
    doubleDirect: boolean = false,
  ) => {
    // clear the previous preview in case offsetSketchCurve throws an error
    ctx2.cadScene.assisGroup.clear();
    ctx2.viewer.requestRender();

    const res = await wsApi.offsetSketchCurve(
      sketchId,
      patternValue[0],
      length,
      isPreview,
      selectChain,
      baseConstruct,
      doubleDirect,
    );

    sketchPreview(res.curves);
  };

  const onSubmit = async ({
    reverse,
    selectChain,
    baseConstruct,
    doubleDirect,
    length,
  }) => {
    if (patternValue && patternValue.length > 0) {
      const res = await wsApi.offsetSketchCurve(
        sketchId,
        patternValue[0],
        reverse ? -length : length,
        false,
        selectChain,
        baseConstruct,
        doubleDirect,
      );
      onClose();
      await renderSketch(sketchId, res);
      picker.clickNull();
      // 执行完需要添加长度标注(圆和圆弧的长度标注目前还不支持)

      const result = await wsApi.getSketchAnnotations(sketchId);

      dimRender().renderDims(result.annotations);
    }
  };
  return (
    <>
      <CommandDialog
        title={title}
        placement='topLeft'
        className='sketchDialog'
        onClose={onClose}
      >
        <CommandFormWrapper>
          <PickInputForFocus2D
            value={patternValue}
            onPick={onPatternData}
            controlled
            className='pick-input-2d'
            placeholder='偏移实体（仅限圆、圆弧或线段）'
            autoFocus
          />
          <NonDialogPickableCommandForm
            formContext={formItemLayout}
            schema={schema}
            extraUiSchema={uiSchema}
            validator={validator}
            onSubmit={onSubmit}
            onChange={onChange}
            showCancel={false}
            submitText='执行'
          />
        </CommandFormWrapper>
      </CommandDialog>
    </>
  );
}

export const cmdOffset: BaseCommand = {
  id: 'CmdOffset',
  label: 'command.skewing',
  icon: 'commands/sketch/excursion',
  group: 'sketch',
  create: (label: string, onClose: () => void, props) => (
    <OffsetCommand
      title={i18n.t(label)}
      onClose={onClose}
      props={props}
      placement='topLeft'
    />
  ),
};
